package com.sharp.schedule.service;

import com.github.pagehelper.PageInfo;
import com.sharp.kernel.constant.CommonConst;
import com.sharp.kernel.constant.err.ErrCodeSys;
import com.sharp.kernel.exception.ServiceException;
import com.sharp.kernel.utils.BeanUtil;
import com.sharp.kernel.utils.ReflectionUtil;
import com.sharp.kernel.validate.Validator;
import com.sharp.kernel.vo.query.QueryRespVO;
import com.sharp.schedule.config.TaskSchedulerConfig;
import com.sharp.schedule.dao.entity.SaSchedule;
import com.sharp.schedule.dao.entity.SaScheduleHistory;
import com.sharp.schedule.dao.repository.SaScheduleHistoryService;
import com.sharp.schedule.dao.repository.SaScheduleService;
import com.sharp.schedule.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * Title: ScheduleService
 * Description: Copyright: Copyright (c) 2019 Company: BHFAE
 *
 * @author Sharp
 * @date 2020/10/16 17:01
 */
@Service
public class ScheduleService {

    @Resource
    private SaScheduleService saScheduleService;
    @Resource
    private SaScheduleHistoryService saScheduleHistoryService;
    @Resource
    private TaskSchedulerConfig taskSchedulerConfig;

    public QueryRespVO<QueryScheduleRes> querySchedule(QueryScheduleReq req) {
        PageInfo<SaSchedule> res = saScheduleService.querySchedule(req.getType(), req.getTemporary(), req.getQueryStartAt(), req.getQueryEndAt(), req.getCurrentPage(), req.getPageSize());
        return new QueryRespVO<>(QueryScheduleRes.class, res);
    }

    public QueryRespVO<QueryScheduleHistoryRes> queryScheduleHistory(QueryScheduleHistoryReq req) {
        PageInfo<SaScheduleHistory> res = saScheduleHistoryService.queryScheduleHistory(req.getScheduleId(), req.getResult(), req.getStartAt(), req.getEndAt(), req.getCurrentPage(), req.getPageSize());
        return new QueryRespVO<>(QueryScheduleHistoryRes.class, res);

    }

    @Transactional(rollbackFor = Exception.class)
    public void update(UpdateScheduleReq req) {
        SaSchedule saSchedule = ReflectionUtil.copy(req, SaSchedule.class);
        validateUpdateScheduleReq(saSchedule);
        if (saSchedule.getId() == null) {
            saScheduleService.insertSelective(saSchedule);
            taskSchedulerConfig.addTask(saSchedule);
        } else {
            saScheduleService.updateByPrimaryKey(saSchedule);
            taskSchedulerConfig.updateTask(saSchedule);
        }
    }

    private void validateUpdateScheduleReq(SaSchedule req) {

        if (req.getParameter() == null) {
            BeanUtil.validateBeanFunction(req.getService(), req.getFunction());
        } else {
            BeanUtil.validateBeanFunction(req.getService(), req.getFunction(), String.class);
        }
        if (StringUtils.isBlank(req.getJobName())) {
            req.setJobName(UUID.randomUUID().toString());
        }
        if (StringUtils.isBlank(req.getStatus())) {
            req.setStatus(CommonConst.YES);
        }
        if (StringUtils.isBlank(req.getTemporary())) {
            req.setTemporary(CommonConst.NO);
        }
        if (StringUtils.isBlank(req.getValid())) {
            req.setValid(CommonConst.YES);
        }

        switch (req.getType()) {
            case TaskSchedulerConfig.SINGLE:
                Validator.assertBlank(req.getCron(), ErrCodeSys.SYS_ERR_MSG, "单次任务不能设置cron表达式");
                break;
            case TaskSchedulerConfig.CRON:
                Validator.assertNotBlank(req.getCron(), ErrCodeSys.SYS_ERR_MSG, "cron任务,cron表达式不能为空");
                break;
            case TaskSchedulerConfig.RATE:
            case TaskSchedulerConfig.DELAY:
                Validator.assertNotNull(req.getStartTime(), ErrCodeSys.SYS_ERR_MSG, "周期任务起始时间不能为空");
                Validator.assertNotNull(req.getPeriod(), ErrCodeSys.SYS_ERR_MSG, "周期任务周期时间不能为空");
                break;
            default:
                throw new ServiceException(ErrCodeSys.SYS_ERR_MSG, "设置定时任务类型错误");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(DeleteScheduleReq req) {
        SaSchedule saSchedule = saScheduleService.selectByPrimaryKey(req.getId());
        if (saSchedule != null) {
            saScheduleService.disable(saSchedule);
            taskSchedulerConfig.delTask(saSchedule);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void schedule(SaSchedule saSchedule) {
        validateUpdateScheduleReq(saSchedule);
        SaSchedule schedule = saScheduleService.getSchedule(saSchedule.getType(), saSchedule.getService(), saSchedule.getFunction(), saSchedule.getParameter());
        if (schedule == null) {
            saScheduleService.insertSelective(saSchedule);
            taskSchedulerConfig.addTask(saSchedule);
        } else {
            saSchedule.setId(schedule.getId());
            saScheduleService.updateByPrimaryKey(saSchedule);
            taskSchedulerConfig.updateTask(saSchedule);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void localSchedule(SaSchedule saSchedule) {
        validateUpdateScheduleReq(saSchedule);
        SaSchedule schedule = saScheduleService.getSchedule(saSchedule.getType(), saSchedule.getService(), saSchedule.getFunction(), saSchedule.getParameter());
        if (schedule == null) {
            saScheduleService.insertSelective(saSchedule);
            taskSchedulerConfig.addLocalTask(saSchedule);
        } else {
            saSchedule.setId(schedule.getId());
            saScheduleService.updateByPrimaryKey(saSchedule);
            taskSchedulerConfig.updateLocalTask(saSchedule);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteSchedule(SaSchedule saSchedule) {
        validateUpdateScheduleReq(saSchedule);
        SaSchedule schedule = saScheduleService.getSchedule(saSchedule.getType(), saSchedule.getService(), saSchedule.getFunction(), saSchedule.getParameter());
        saScheduleService.disableByPrimaryKey(schedule.getId());
        taskSchedulerConfig.delTask(saSchedule);
    }
}
